package com.own.business.login.core.core;

import com.own.component.common.hook.BaseRoleHook;
import com.own.component.common.login.core.UserStatusHook;
import com.own.component.common.login.user.BaseLoginUser;
import com.own.component.store.core.Store;
import com.own.component.store.core.util.PermissionCacheUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * RoleSpringHook
 *
 * @author chenxueli
 * @date 2022-08-09 15:28:00
 */
@Slf4j
@Component
@SuppressWarnings("all")
public class RoleSpringHook implements ApplicationContextAware, ApplicationListener<ApplicationEvent>, UserStatusHook {

    private static final List<BaseRoleHook> ROLE_MANAGER = new ArrayList<>();
    private static final String ROLE_NAME_FIELD = "rn:";
    private static final String MENU_OPERATION_FIELD = "mo:";
    private static ApplicationContext applicationContext;
    @Resource
    private Store<String> store;

    @Resource
    private PermissionCacheUtil permissionCacheUtil;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        RoleSpringHook.applicationContext = context;
    }

    /**
     * 处理所有的获取用户信息的内容
     * <p>
     * 如果菜单和角色信息修改此处的缓存会失效
     *
     * @param loginUser 登录的用户信息
     */
    public Set<String> get(BaseLoginUser loginUser) {
        // 从缓存中获取角色名称列表信息
        var set = store.set();
        var key = ROLE_NAME_FIELD + permissionCacheUtil.getGlobalTimestamp() + ":" + loginUser.userId();
        if (set.contains(key)) {
            return set.members(key);
        }
        // 获取角色信息
        var roleNameList = ROLE_MANAGER
                .stream()
                .map(service -> service.getRoleNameList(loginUser))
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());
        // 存入缓存，并设置过期时间
        set.add(key, roleNameList);
        set.expire(key, Duration.ofMinutes(60));
        return roleNameList;
    }

    /**
     * 获取当前模块的操作权限列表
     *
     * @param loginUser 登录的用户信息
     * @param module    模块信息
     * @return 操作权限列表
     */
    public Set<String> module(BaseLoginUser loginUser, String module) {
        // 从缓存中获取角色名称列表信息
        var map = store.map();
        var key = MENU_OPERATION_FIELD
                + permissionCacheUtil.getGlobalTimestamp()
                + ":"
                + permissionCacheUtil.getUserRoleTimestamp(loginUser.userId())
                + ":"
                + loginUser.client()
                + ":"
                + loginUser.userId();
        if (map.contains(key, module)) {
            var string = map.get(key, module);
            if (StringUtils.isBlank(string)) {
                return Collections.emptySet();
            }
            return Arrays.stream(string.split(",")).collect(Collectors.toSet());
        }
        var list = ROLE_MANAGER
                .stream()
                .map(service -> service.getModuleOperation(loginUser, module))
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());
        // 存入缓存，并设置过期时间
        map.put(key, module, list.stream().collect(Collectors.joining(",")));
        map.expire(key, Duration.ofMinutes(10));
        return list;
    }

    /**
     * 清除信息
     *
     * @param loginUser 登录的用户信息
     */
    @Override
    public void clear(BaseLoginUser loginUser) {
        var globalTimestamp = permissionCacheUtil.getGlobalTimestamp();
        store.set().remove(ROLE_NAME_FIELD + globalTimestamp + ":" + loginUser.userId());
        store.map().remove(MENU_OPERATION_FIELD + globalTimestamp + ":" + permissionCacheUtil.getUserRoleTimestamp(loginUser.userId()) + ":" + loginUser.client() + ":" + loginUser.userId());
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationReadyEvent) {
            applicationContext.getBeansOfType(BaseRoleHook.class).forEach((key, service) -> {
                log.debug("角色信息接口===>【{}】完成注册", key);
                ROLE_MANAGER.add(service);
            });
        }
    }

}
